// Copyright 2024 The Perses Authors
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package common

import (
	"encoding/json"
	"fmt"
)

type (
	TimeUnit       string
	PercentageUnit string
	ThroughputUnit string
	CurrencyUnit   string
	BytesUnit      string
)

const (
	NanoSecondsUnit        TimeUnit       = "nanoseconds"
	MicroSecondsUnit       TimeUnit       = "microseconds"
	MilliSecondsUnit       TimeUnit       = "milliseconds"
	SecondsUnit            TimeUnit       = "seconds"
	MinutesUnit            TimeUnit       = "minutes"
	HoursUnit              TimeUnit       = "hours"
	DaysUnit               TimeUnit       = "days"
	WeeksUnit              TimeUnit       = "weeks"
	MonthsUnit             TimeUnit       = "months"
	YearsUnit              TimeUnit       = "years"
	PercentUnit            PercentageUnit = "percent"
	PercentDecimalUnit     PercentageUnit = "percent-decimal"
	DecimalUnit            string         = "decimal"
	BinaryBitsUnit         BytesUnit      = "bits"
	DecimalBitsUnit        BytesUnit      = "decbits"
	BinaryBytesUnit        BytesUnit      = "bytes"
	DecimalBytesUnit       BytesUnit      = "decbytes"
	BitsPerSecondsUnit     ThroughputUnit = "bits/sec"
	BitsDecPerSecondsUnit  ThroughputUnit = "decbits/sec"
	BytesPerSecondsUnit    ThroughputUnit = "bytes/sec"
	BytesDecPerSecondsUnit ThroughputUnit = "decbytes/sec"
	CountsPerSecondsUnit   ThroughputUnit = "counts/sec"
	EventsPerSecondsUnit   ThroughputUnit = "events/sec"
	MessagesPerSecondsUnit ThroughputUnit = "messages/sec"
	OpsPerSecondsUnit      ThroughputUnit = "ops/sec"
	PacketsPerSecondsUnit  ThroughputUnit = "packets/sec"
	ReadsPerSecondsUnit    ThroughputUnit = "reads/sec"
	RecordsPerSecondsUnit  ThroughputUnit = "records/sec"
	RequestsPerSecondsUnit ThroughputUnit = "requests/sec"
	RowsPerSecondsUnit     ThroughputUnit = "rows/sec"
	WritesPerSecondsUnit   ThroughputUnit = "writes/sec"
	AustralianDollarUnit   CurrencyUnit   = "aud"
	CanadianDollarUnit     CurrencyUnit   = "cad"
	SwissFrancUnit         CurrencyUnit   = "chf"
	RenminbiUnit           CurrencyUnit   = "cny"
	EuroUnit               CurrencyUnit   = "eur"
	PoundUnit              CurrencyUnit   = "gbp"
	HongKongDollarUnit     CurrencyUnit   = "hkd"
	IndianRupeeUniit       CurrencyUnit   = "inr"
	YenUnit                CurrencyUnit   = "jpy"
	SouthKoreanWonUnit     CurrencyUnit   = "krw"
	NorwegianKroneUnit     CurrencyUnit   = "nok"
	NewZealandDollarUnit   CurrencyUnit   = "nzd"
	SwedishKronaDollarUnit CurrencyUnit   = "sek"
	SingaporeDollarUnit    CurrencyUnit   = "sgd"
	USDollarUnit           CurrencyUnit   = "usd"
)

type Format struct {
	Unit          *string `json:"unit,omitempty"          yaml:"unit,omitempty"`
	DecimalPlaces int     `json:"decimalPlaces,omitempty" yaml:"decimalPlaces,omitempty"`
	ShortValues   bool    `json:"shortValues,omitempty"   yaml:"shortValues,omitempty"`
}

func (f *Format) UnmarshalJSON(data []byte) error {
	type plain Format
	var tmp Format
	if err := json.Unmarshal(data, (*plain)(&tmp)); err != nil {
		return err
	}
	if err := (&tmp).validate(); err != nil {
		return err
	}
	*f = tmp
	return nil
}

func (f *Format) UnmarshalYAML(unmarshal func(any) error) error {
	var tmp Format
	type plain Format
	if err := unmarshal((*plain)(&tmp)); err != nil {
		return err
	}
	if err := (&tmp).validate(); err != nil {
		return err
	}
	*f = tmp
	return nil
}

func (f *Format) validate() error {
	if f.Unit == nil {
		return nil
	}
	switch *f.Unit {
	case string(NanoSecondsUnit), string(MicroSecondsUnit), string(MilliSecondsUnit), string(SecondsUnit), string(MinutesUnit),
		string(HoursUnit), string(DaysUnit), string(WeeksUnit), string(MonthsUnit),
		string(YearsUnit), string(PercentUnit), string(PercentDecimalUnit), DecimalUnit, string(BinaryBytesUnit), string(DecimalBytesUnit),
		string(BitsPerSecondsUnit), string(BitsDecPerSecondsUnit), string(BytesPerSecondsUnit), string(BytesDecPerSecondsUnit), string(CountsPerSecondsUnit), string(EventsPerSecondsUnit),
		string(MessagesPerSecondsUnit), string(OpsPerSecondsUnit), string(PacketsPerSecondsUnit),
		string(ReadsPerSecondsUnit), string(RecordsPerSecondsUnit), string(RequestsPerSecondsUnit),
		string(RowsPerSecondsUnit), string(WritesPerSecondsUnit), string(AustralianDollarUnit), string(CanadianDollarUnit),
		string(SwissFrancUnit), string(RenminbiUnit), string(EuroUnit), string(PoundUnit),
		string(HongKongDollarUnit), string(IndianRupeeUniit), string(YenUnit), string(SouthKoreanWonUnit),
		string(NorwegianKroneUnit), string(NewZealandDollarUnit):
		return nil
	default:
		return fmt.Errorf("unknown format")
	}
}
